package presentation.web;

import java.text.SimpleDateFormat ;
import java.util.Arrays ;
import java.util.Calendar ;
import java.util.Date ;
import java.util.Set ;

import jaxcent.HtmlButton ;
import jaxcent.HtmlInputRadio ;
import jaxcent.HtmlPara ;
import jaxcent.HtmlSelect ;
import jaxcent.HtmlTable ;
import jaxcent.HtmlTableCell ;
import jaxcent.HtmlTableRow ;
import jaxcent.HtmlTextArea ;
import jaxcent.JaxcentPage ;
import presentation.UIPost ;
import util.DateTools ;
import util.Log ;
import util.NotFoundException ;
import util.Subsystem ;
import domain.searchEngine.SearchResult ;

/**
 * The Class SearchPage. Responsible for searching by content ,author or date
 *
 * @author Hadas
 */
public class SearchPage extends MainPage
{
	/**
	 * The Class TableCell.
	 * override the method on Click and contains the correspond message
	 */
	private class TableCell extends HtmlTableCell
	{
		/** The correspond message of the row. */
		private String messageContent;

		/**
		 * Instantiates a new table row.
		 *
		 * @param jp the JaxcentPage
		 * @param tbRow the HtmlTableRow
		 * @param index the index in the row
		 * @param content the message
		 */
		public TableCell(final JaxcentPage jp,final HtmlTableRow tbRow, final int index,final String content)
		{
			super(jp,tbRow,index);
			this.messageContent = content;
		}

		/**
		 * OnClick method which present the content of the message when pressing on
		 * the message.
		 */
		@Override
		protected void onClick()
		{
			try
			{
				SearchPage.this.getCurrentMes().setValue(this.messageContent);
			}
			catch (Exception e)
			{
				SearchPage.this.navigateToErrorPage(e, SearchPage.this.getCurrentMes()) ;
			}
		}
	}//End of private class

	private static final int LOWEST_YEAR = 2005 ;
	private static final int HIGHEST_YEAR = DateTools.get(new Date(), Calendar.YEAR) ;
	private static final int MONTHS_IN_YEAR = 12 ;
	private static final int DAYS_IN_MONTH = 31 ;

	/** The searchbycontent radio option. */
	private HtmlInputRadio searchByContentRadio;

	/** The searchbyauthor radio option. */
	private HtmlInputRadio searchByAuthorRadio;

	/** The searchbydate radio option. */
	private HtmlInputRadio searchByDateRadio;

	/** The content of the search by content. */
	private HtmlTextArea content;

	/** The content of the search by author. */
	private HtmlTextArea author;

	/** The current message picked by the user. */
	private HtmlTextArea currentMessage;

	/** The resultset messages. */
	private HtmlTable resultSetCont;

	/** The from day for date search. */
	private HtmlSelect fromDay;

	/** The from month for date search. */
	private HtmlSelect fromMonth;

	/** The from year for date search. */
	private HtmlSelect fromYear;

	/** The to day for date search. */
	private HtmlSelect toDay;

	/** The to month for date search. */
	private HtmlSelect toMonth;

	/** The to year for date search. */
	private HtmlSelect toYear;

	/** The errors paragraph s error messages to user. */
	private HtmlPara errorsPara;

	private HtmlPara messageToUser;

	/**
	 * Instantiates a new search page.
	 *
	 */
	public SearchPage()
	{
		super();
		try
		{
			this.content = new HtmlTextArea(this,"contentText");
			this.author = new HtmlTextArea(this,"authorText");
			this.currentMessage = new HtmlTextArea(this,"chosenMes");
			this.resultSetCont = new HtmlTable(this,"resultSetCont");
			this.currentMessage.setReadOnly(true);
			this.content.setDisabled(true);
			this.content.setValue("");
			this.author.setDisabled(true);
			this.author.setValue("");
			this.setParagrhps();
			this.makeRadio();
			this.makeButton();
			this.createSelect();
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null);
		}
	}

	/**
	 * Return the Text area which contains the message that the user picks.
	 *
	 * @return the an HtmlTextArea
	 */
	public HtmlTextArea getCurrentMes()
	{
		return this.currentMessage;
	}

	/**
	 * Handlers for choosing the author radio.
	 * disable all other buttons and all correspond text area or select options
	 * enable all correspond text area or select options
	 */
	protected void authorRadioHandler()
	{
		try
		{
			this.searchByAuthorRadio.setChecked(true);
			this.author.setDisabled(false);
			this.content.setDisabled(true);
			this.setSelected(true);
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Handlers for choosing the content radio.
	 * disable all other buttons and all correspond text area or select options
	 * enable all correspond text area or select options
	 */
	protected void contentRadioHandler()
	{
		try
		{
			this.searchByContentRadio.setChecked(true);
			this.content.setDisabled(false);
			this.author.setDisabled(true);
			this.setSelected(true);
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Handlers for choosing the Date radio.
	 * disable all other buttons and all correspond text area or select options
	 * enable all correspond text area or select options
	 */
	protected void dateRadioHandler()
	{
		try
		{
			this.searchByDateRadio.setChecked(true);
			this.setSelected(false);
			this.content.setDisabled(true);
			this.author.setDisabled(true);
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Search button handler.
	 * handles all type of search
	 */
	protected void htmlButtonHandler()
	{
		try
		{
			this.errorsPara.setInnerHTML("");
			this.messageToUser.setInnerHTML("");
			this.currentMessage.setValue("");
			if(this.searchByContentRadio.getChecked())
			{
				this.searchByContent();
			}
			else if(this.searchByAuthorRadio.getChecked())
			{
				this.searchByAuthor();
			}
			else if (this.searchByDateRadio.getChecked())
			{
				this.searchByDate();
			}
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Initialize the date fields.
	 */
	@Override
	protected void onLoad()
	{
		super.onLoad();
		try
		{
			Date today = new Date() ;
			final int todaysDay = DateTools.get(today, Calendar.DAY_OF_MONTH) ;
			final int todaysMonth = DateTools.get(today, Calendar.MONTH) ;
			final int todaysYear = DateTools.get(today, Calendar.YEAR) ;

			final int todaysDayIndex = todaysDay - 1 ;
			final int todaysMonthIndex = todaysMonth ;
			final int todaysYearIndex = SearchPage.HIGHEST_YEAR - todaysYear ;

			this.fromDay.setSelectedIndex(todaysDayIndex);
			this.fromMonth.setSelectedIndex(todaysMonthIndex);
			this.fromYear.setSelectedIndex(todaysYearIndex);

			this.toDay.setSelectedIndex(todaysDayIndex);
			this.toMonth.setSelectedIndex(todaysMonthIndex);
			this.toYear.setSelectedIndex(todaysYearIndex);
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, this.fromDay);
		}
	}

	/**
	 * Adds the link to parent thread of the post.
	 *
	 * @param post the current post
	 *
	 * @return the link of the parent thread
	 */
	private String addLinkToThread(final UIPost post)
	{
		try
		{
			String page = MainPage.pageLinks.get("view thread");
			long threadParentId = post.getThreadParentId();
			String threadTopic = this.getForumLogic().getThread(threadParentId).getTopic() ;
			return MainPage.makeLinkOpenInNewPage(page, threadTopic, "thread=" + threadParentId);
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null);
			return "";
		}
	}

	/**
	 * Check date correctness.
	 *
	 * @param day the day
	 * @param month the month
	 *
	 * @return true, if date is correct
	 */
	private boolean checkDateCorrectness(final String day,final String month)
	{
		try
		{
			if(month.equals("2") && Integer.parseInt(day)> 28)
			{
				return false;
			}
			if(((month.equals("11")) || (month.equals("6"))|| (month.equals("4"))|| (month.equals("9"))) && Integer.parseInt(day)> 30)
			{
				return false;
			}
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null);
		}
		return true;
	}//End of checkDateCorrectnesss

	/**
	 * Creates the select options for search by date :
	 * the from date and the to date.
	 */
	private void createSelect()
	{
		try
		{
			this.fromDay = new HtmlSelect(this,"fromDay");
			this.fromMonth = new HtmlSelect(this,"fromMonth");
			this.fromYear = new HtmlSelect(this,"fromYear");
			this.toDay = new HtmlSelect(this,"toDay");
			this.toMonth = new HtmlSelect(this,"toMonth");
			this.toYear = new HtmlSelect(this,"toYear");
			this.setSelected(true);
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null);
		}
		/* Initialize the options in each select box */
		try
		{
			//Init days
			for(int i=1; i<=SearchPage.DAYS_IN_MONTH;i++){
				this.fromDay.insertOption(i, Integer.toString(i));
				this.toDay.insertOption(i, Integer.toString(i));
			}
			//Init months
			for(int i=1; i<=SearchPage.MONTHS_IN_YEAR;i++){
				this.fromMonth.insertOption(i, Integer.toString(i));
				this.toMonth.insertOption(i, Integer.toString(i));
			}
			//Init years
			int j = 1;
			for(int i=SearchPage.HIGHEST_YEAR; i>=SearchPage.LOWEST_YEAR;i--){
				this.fromYear.insertOption(j, Integer.toString(i));
				this.toYear.insertOption(j, Integer.toString(i));
				j++;
			}
		}
		catch(Exception e)
		{
			this.navigateToErrorPage("Error in date components", null) ;
		}
	}

	/**
	 * Create the search button and the correspond handler.
	 */
	private void makeButton(){
		try
		{
			new HtmlButton(this,"searchButton"){
		        @Override protected void onClick(){
		        	SearchPage.this.htmlButtonHandler();
		        }
		    };
		}
		catch(Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Make radio buttons for choosing between search operations.
	 */
	private void makeRadio()
	{
		try
		{
			//init the searchByContentRadio and the action onClick
			this.searchByContentRadio = new HtmlInputRadio(this,"searchContent"){
				@Override protected void onClick(){
					SearchPage.this.contentRadioHandler();
				}
			};
			//init the searchByAuthorRadio and the action onClick
			this.searchByAuthorRadio = new HtmlInputRadio(this,"searchAuthor"){
				@Override protected void onClick(){
					SearchPage.this.authorRadioHandler();
				}
			};
			//init the searchByDateRadio and the action onClick
			this.searchByDateRadio = new HtmlInputRadio(this,"searchDate"){
				@Override protected void onClick(){
					SearchPage.this.dateRadioHandler();
				}
			};
		}
		catch(Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Present result. Display all result in corresponding places
	 *
	 * @param results the results set of messages
	 */
	private void presentResult(final Set<SearchResult> results)
	{
		try
		{
			int i = 0;
			this.resultSetCont.deleteAllRows();
			this.resultSetCont.setBorder(1);
			if(results.isEmpty())
			{
				this.resultSetCont.insertRow(i, new String[2]);
				HtmlTableRow row = new HtmlTableRow(this,this.resultSetCont,i);
				row.insertCell(0, "No matching");
			}
			else
			{
				this.messageToUser.setInnerHTML("Press score to view the message. Press link to navigate towards topic page");
				SearchResult[] sortedResults = new SearchResult[results.size()];
				sortedResults = results.toArray(sortedResults);
				Arrays.sort(sortedResults);
				for(SearchResult searchResult: sortedResults)
				{
					this.resultSetCont.insertRow(i, new String[2]);
					String writer = this.getForumLogic().getMemberById(searchResult.getPost().getWriterId()).getUsername();
					SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
					String timeOfPost = df.format(searchResult.getPost().getDate());
					String messageContent = "Author: "+writer+"\nCreated: "+timeOfPost+"\nContent: "+searchResult.getPost().getMessage();
					HtmlTableRow row = new HtmlTableRow(this,this.resultSetCont,i);
					HtmlTableCell tc = new TableCell(this,row,0,messageContent);
					tc.setInnerHTML((i+1)+". score is "+searchResult.getScore());
					row.insertCell(1, this.addLinkToThread(searchResult.getPost()));
					i++;
				}
			}
		}
		catch(NotFoundException e)
		{
			Log.getLogger(Subsystem.PRESENTATION_MODEL).info("writer of post was not found");
			this.showMessageDialog("Error occur while trying to find author message, please try again");
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Search by author.
	 * Read the author from HTML page and search according to author name
	 */
	private void searchByAuthor()
	{
		try
		{
			String textInAuthor = this.author.getValue();
			if(textInAuthor.equals(""))
			{
				this.errorsPara.setInnerHTML("No parameter to search, Please Insert");
			}
			else
			{
				if((textInAuthor.charAt(textInAuthor.length()-1) < 33) || (textInAuthor.charAt(textInAuthor.length()-1) > 126))
				{
					textInAuthor = textInAuthor.substring(0, textInAuthor.length()-1);
				}
				Log.getLogger(Subsystem.PRESENTATION_MODEL).finest("searching by author - waits for server answer");
				Set<SearchResult> results = this.getForumLogic().searchByAuthor(textInAuthor);
				this.presentResult(results);
			}
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Search by content.
	 * Read the content from HTML page and search according to content
	 */
	private void searchByContent()
	{
		try
		{
			String textInContent = this.content.getValue();
			if(textInContent.equals(""))
			{
				this.errorsPara.setInnerHTML("No parameter to search, Please Insert");
			}
			else
			{
				if((textInContent.charAt(textInContent.length()-1) < 33) || (textInContent.charAt(textInContent.length()-1) > 126))
				{
					textInContent = textInContent.substring(0, textInContent.length()-1);
				}
				Log.getLogger(Subsystem.PRESENTATION_MODEL).finest("searching by content - waits for server answer");
				Set<SearchResult> results = this.getForumLogic().searchByContent(textInContent);
				this.presentResult(results);
			}
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Search by date.
	 * Read the dates from HTML page and search according to from until to date
	 */
	private void searchByDate()
	{
		try
		{
			String dayF = this.fromDay.getOption(this.fromDay.getSelectedIndex()).getValue();
			String monthF = this.fromMonth.getOption(this.fromMonth.getSelectedIndex()).getValue();
			String yearF = this.fromYear.getOption(this.fromYear.getSelectedIndex()).getValue();
			String dayT = this.toDay.getOption(this.toDay.getSelectedIndex()).getValue();
			String monthT = this.toMonth.getOption(this.toMonth.getSelectedIndex()).getValue();
			String yearT = this.toYear.getOption(this.toYear.getSelectedIndex()).getValue();
			if(!this.checkDateCorrectness(dayF, monthF) || !this.checkDateCorrectness(dayT, monthT))
			{
				this.errorsPara.setInnerHTML("Invalid date, correct and search again");
				return;
			}

			/*
			 * we could have just used dayT+1 and give up the whole hour handling.
			 * however, it would be less obvious and more prone to bugs.
			 */
			String fromDate = dayF+"-"+monthF+"-"+yearF + "-00:00:00";
			String toDate = dayT+"-"+monthT+"-"+yearT + "-23:59:59";
			SimpleDateFormat formatter = new SimpleDateFormat("d-M-yyyy-hh:mm:ss");

			Date startDate = formatter.parse(fromDate) ;
			Date finishDate = formatter.parse(toDate);

			Set<SearchResult> results = this.getForumLogic().searchByDate(startDate,finishDate );
			this.presentResult(results);
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, null) ;
		}
	}

	/**
	 * Sets the errors paragraph with initialize empty text.
	 */
	private void setParagrhps()
	{
		try
		{
			this.errorsPara = new HtmlPara(this,"errorPara");
			this.errorsPara.setInnerHTML("");
			this.messageToUser = new HtmlPara(this,"messageToUser");
			this.messageToUser.setInnerHTML("");
		}
		catch (Exception e)
		{
			this.navigateToErrorPage(e, this.errorsPara) ;
		}
	}

	/**
	 * Sets the select date options to be enabled or disabled.
	 *
	 * @param par the new selected
	 */
	private void setSelected(final boolean par)
	{
		try
		{
			this.fromDay.setDisabled(par);
			this.fromMonth.setDisabled(par);
			this.fromYear.setDisabled(par);
			this.toDay.setDisabled(par);
			this.toMonth.setDisabled(par);
			this.toYear.setDisabled(par);
		}
		catch (Exception e)
		{
			this.navigateToErrorPage("Error in date components", null) ;
		}
	}
}
